namespace Xmef.Serializer
{
    using System;
    using System.IO;
    using System.Xml;
    using System.Xml.Serialization;
    using Xmef.Interfaces;
    using Xmef.Library;
    using Xmef.Serializer.Internal;
    using System.Runtime.Serialization.Formatters.Binary;

    [Serializable]
    public abstract class XmlStreamSerializer<T> : PluginIdentity, IXmlStreamSerializer<T>
    {
        [NonSerialized]
        private static readonly XmlFormatterCache _formatters;
        private T _object;
        [NonSerialized]
        private static readonly XmlSerializerCache _serializers;
        private readonly Type _type;

        static XmlStreamSerializer()
        {
            XmlStreamSerializer<T>._formatters = new XmlFormatterCache();
            XmlStreamSerializer<T>._serializers = new XmlSerializerCache();
        }

        protected XmlStreamSerializer()
        {
            this._type = typeof(T);
        }

        protected virtual bool Deserialize(Stream input, IXmlTypeFormatter formatter)
        {
            this._object = default(T);
            try
            {
                IXmlRuntimeSerializerInternal serializer = Runtime.GetSerializer<T>(formatter);
                if (serializer != null)
                {
                    using (XmlReader xmlReader = XmlReader.Create(input, serializer.ReaderSettings))
                    {
                        XmlSerializer cache = XmlStreamSerializer<T>._serializers[serializer];
                        if (cache != null)
                        {
                            object result = cache.Deserialize(xmlReader);
                            if (result != null)
                            {
                                this._object = (T) result;
                            }
                        }
                    }
                }
                return true;
            }
            catch (ApplicationException ex)
            {
                LogHelper.WriteErrorSync(ex);
            }
            return false;
        }

        protected bool OverrideRuntimeSerializer(IXmlTypeFormatter formatter, XmlSerializer value)
        {
            IXmlRuntimeSerializerInternal serializer = Runtime.GetSerializer<T>(formatter);
            return ((serializer != null) && XmlStreamSerializer<T>._serializers.Override(serializer, value));
        }

        protected virtual bool Serialize(T obj, Stream output, IXmlTypeFormatter formatter)
        {
            this._object = obj;
            try
            {
                IXmlRuntimeSerializerInternal serializer = Runtime.GetSerializer<T>(formatter);
                if (serializer != null)
                {
                    using (XmlWriter xmlWriter = XmlWriter.Create(output, serializer.WriterSettings))
                    {
                        XmlSerializer cache = XmlStreamSerializer<T>._serializers[serializer];
                        if (cache != null)
                        {
                            cache.Serialize(xmlWriter, obj);
                        }
                    }
                    return true;
                }
            }
            catch (ApplicationException ex)
            {
                LogHelper.WriteErrorSync(ex);
            }
            return false;
        }

        bool IXmlStreamSerializer<T>.Deserialize(Stream input)
        {
            IXmlTypeFormatter formatter = XmlStreamSerializer<T>._formatters[this._type];
            return this.Deserialize(input, formatter);
        }

        bool IXmlStreamSerializer<T>.Deserialize(Stream input, IXmlRuntimeFormatter value)
        {
            IXmlTypeFormatter formatter = XmlStreamSerializer<T>._formatters[value];
            return ((formatter != null) && this.Deserialize(input, formatter));
        }

        bool IXmlStreamSerializer<T>.Serialize(T obj, Stream output)
        {
            IXmlTypeFormatter formatter = XmlStreamSerializer<T>._formatters[this._type];
            return this.Serialize(obj, output, formatter);
        }

        bool IXmlStreamSerializer<T>.Serialize(T obj, Stream output, IXmlRuntimeFormatter value)
        {
            IXmlTypeFormatter formatter = XmlStreamSerializer<T>._formatters[value];
            return ((formatter != null) && this.Serialize(obj, output, formatter));
        }

        public T RuntimeObject
        {
            get
            {
                return this._object;
            }
        }

        protected void InitializeRuntimeObject(T obj)
        {
            this._object = obj;
        }

        protected IXmlTypeFormatter XmlTypeFormatter
        {
            get
            {
                return XmlStreamSerializer<T>._formatters[this._type];
            }
        }
    }
}

